package com.whfc.emp.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.whfc.common.exception.BizException;
import com.whfc.common.result.ResultEnum;
import com.whfc.common.util.DateUtil;
import com.whfc.common.third.juhe.JuheFaceVerifyProperties;
import com.whfc.emp.dto.AppEmpDTO;
import com.whfc.emp.dto.FaceCheckInResultDTO;
import com.whfc.emp.entity.AppWorkPlan;
import com.whfc.emp.entity.ClassMeeting;
import com.whfc.emp.entity.ClassMeetingSign;
import com.whfc.emp.param.FaceCheckInParam;
import com.whfc.emp.service.*;
import com.whfc.fuum.entity.SysEmpUser;
import com.whfc.fuum.service.SysUserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@DubboService(interfaceClass = FaceRecognitionCheckInService.class, version = "1.0.0", timeout = 30000)
public class FaceRecognitionCheckInServiceImpl implements FaceRecognitionCheckInService {

    @Autowired
    private JuheFaceVerifyProperties juheFaceVerifyProperties;

    @Autowired
    private ClassMeetingService classMeetingService;

    @Autowired
    private ClassMeetingSignService classMeetingSignService;

    @Autowired
    private AppWorkPlanService appWorkPlanService;

    @Autowired
    private AppEmpService appEmpService;

    @DubboReference(interfaceClass = SysUserService.class, version = "1.0.0", timeout = 30000)
    private SysUserService sysUserService;

    @Override
    public FaceCheckInResultDTO faceCheckIn(FaceCheckInParam param) throws BizException {
        FaceCheckInResultDTO result = new FaceCheckInResultDTO();

        // 1. 验证参数
        validateParam(param);

        // 2. 查询班会信息
        ClassMeeting meeting = classMeetingService.selectByPrimaryKey(param.getMeetingId());
        if (meeting == null) {
            throw new BizException(ResultEnum.FAILURE.getCode(), "班会不存在");
        }

        SysEmpUser sysEmpUser = sysUserService.getEmpUserByEmpId(param.getEmpId());
        if (sysEmpUser == null) {
            throw new BizException(ResultEnum.FAILURE.getCode(), "未绑定系统账号");
        }

        // 3. 查询签到记录
        ClassMeetingSign classMeetingSign = classMeetingSignService.selectByPrimaryIdAndUserId(
                param.getMeetingId(), sysEmpUser.getSysUserId());

        AppEmpDTO appEmpDTO = appEmpService.getEmpInfo(param.getEmpId());

        if (appEmpDTO == null || StringUtils.isEmpty(appEmpDTO.getEmpName()) || StringUtils.isEmpty(appEmpDTO.getIdCardNo())){
            throw new BizException(ResultEnum.FAILURE.getCode(), "用户身份信息不全");
        }
        param.setIdCardNo(appEmpDTO.getIdCardNo());
        param.setUserName(appEmpDTO.getEmpName());
        // 4. 获取工作计划ID
//        Integer planId = param.getPlanId() != null ? param.getPlanId() : meeting.getPlanId();

        // 6. 调用聚合数据人脸对比认证接口
        Double similarityScore = callJuheFaceVerifyApi(param);

        // 7. 与工作计划施工人员人脸库比对（使用聚合数据返回的相似度）
        Double maxScore = similarityScore;
        boolean isMatch = similarityScore >= juheFaceVerifyProperties.getSimilarityThreshold();

        // 8. 根据比对结果处理
        if (isMatch) {
            // 匹配成功，签到成功
            if (classMeetingSign == null) {
                classMeetingSign = new ClassMeetingSign();
                classMeetingSign.setMeetingId(meeting.getId());
                classMeetingSign.setSignTime(DateUtil.formatDateTime(new Date()));
                classMeetingSign.setSignStatus(1);
                classMeetingSign.setEmpId(param.getEmpId());        // 设置签到人员id
                classMeetingSign.setCreatorId(param.getCreatorId()); // 设置创建者id
                classMeetingSignService.insertSelective(classMeetingSign);
            } else {
                classMeetingSign.setSignTime(DateUtil.formatDateTime(new Date()));
                classMeetingSign.setSignStatus(1);
                classMeetingSign.setEmpId(param.getEmpId());        // 更新签到人员id
                classMeetingSignService.updateByPrimaryKey(classMeetingSign);
            }

            result.setSuccess(true);
            result.setMessage("签到成功");
            result.setSignStatus(1);
            result.setFaceScore(maxScore);

            log.info("用户{}人脸识别签到成功，班会ID: {}，比对分数: {}",
                    param.getEmpId(), param.getMeetingId(), maxScore);
        } else {
            // 匹配失败，设置报警信息
            result.setSuccess(false);
            result.setMessage("人脸识别失败：非工作计划入场施工人员");
            result.setSignStatus(0);
            result.setFaceScore(maxScore);

//            String title = "班会人脸签到报警";
//            String warnMessage = String.format(
//                    "检测到非授权人员尝试签到：用户ID=%s，用户名=%s，班会ID=%d，比对分数=%.2f",
//                    param.getUserId(), param.getUserName(), param.getMeetingId(), maxScore);
//
//            List<AppMsgToUserDTO> toUserDTOS = appWorkPlanService.sendAlarmMessageToWorkPlanGuardians(title, warnMessage, planId);
//            if (toUserDTOS != null && !toUserDTOS.isEmpty()){
//                List<String> alarmUser = toUserDTOS.stream().map(AppMsgToUserDTO::getUsername).collect(Collectors.toList());
//                log.warn("发送告警信息:{}", alarmUser);
//            }
            log.warn("用户{}人脸识别签到失败，班会ID: {}，比对分数: {}",
                            param.getEmpId(), param.getMeetingId(), maxScore);
        }

        return result;
    }

    /**
     * 调用聚合数据人脸对比认证接口
     * @param param 人脸识别签到参数
     * @return 相似度分数，如果调用失败返回null
     */
    private Double callJuheFaceVerifyApi(FaceCheckInParam param) throws BizException {
        try {
            // 构建请求参数
            HashMap<String, String> map = new HashMap<>();
            map.put("key", juheFaceVerifyProperties.getApiKey());
            map.put("idcard", param.getIdCardNo());
            map.put("realname", param.getUserName());
            // 处理人脸图片base64编码（去除前缀）
            String faceImage = param.getFaceImage();
            if (faceImage.contains(",")) {
                faceImage = faceImage.split(",")[1];
            }
            map.put("image", faceImage);
            map.put("thousand", ""); // 千分位，可选参数

            // 创建HTTP连接
            URL url = new URL(juheFaceVerifyProperties.getApiUrl());
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("POST");
            connection.setDoOutput(true);
            connection.setConnectTimeout(juheFaceVerifyProperties.getConnectTimeout());
            connection.setReadTimeout(juheFaceVerifyProperties.getReadTimeout());

            // 发送请求参数
            String urlParameters = params(map);
            try (OutputStream os = connection.getOutputStream()) {
                byte[] input = urlParameters.getBytes(StandardCharsets.UTF_8);
                os.write(input, 0, input.length);
            }

            // 读取响应
            BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
            String inputLine;
            StringBuffer response = new StringBuffer();
            while ((inputLine = in.readLine()) != null) {
                response.append(inputLine);
            }
            in.close();

            // 解析响应
            String responseStr = response.toString();
            log.info("聚合数据人脸对比接口响应: {}", responseStr);
            JSONObject object = JSON.parseObject(responseStr);
            JSONObject result = object.getJSONObject("result");
            if (result == null){
                throw new BizException(ResultEnum.FAILURE.getCode(), "聚合数据人脸对比服务异常:"+responseStr);
            }
            // 解析JSON响应
            int res = result.getInteger("res");
            if (res == 1) {
                // 提取相似度分数
                String similarityStr = object.getJSONObject("result").getString("score");
                if (similarityStr != null) {
                    return Double.parseDouble(similarityStr);
                } else {
                    throw new BizException(ResultEnum.FAILURE.getCode(), "无法解析相似度分数");
                }
            } else {
                // 解析错误信息并抛出具体异常
                String errorMessage = result.getString("message");
                log.error("聚合数据人脸对比接口调用失败: {}", errorMessage);
                throw new BizException(ResultEnum.FAILURE.getCode(), errorMessage);
            }

        } catch (BizException e) {
            // 重新抛出业务异常
            throw e;
        } catch (Exception e) {
            log.error("调用聚合数据人脸对比接口异常: {}", e.getMessage(), e);
            throw new BizException(ResultEnum.FAILURE.getCode(), "人脸比对服务暂时不可用，请稍后重试");
        }
    }

    /**
     * 从响应中提取相似度分数
     * @param response JSON响应字符串
     * @return 相似度分数字符串
     */
    private String extractSimilarityFromResponse(String response) {
        try {
            // 简单的JSON解析，实际应该使用JSON库
            if (response.contains("\"similarity\":")) {
                String similarityPart = response.substring(response.indexOf("\"similarity\":") + 12);
                similarityPart = similarityPart.substring(0, similarityPart.indexOf(","));
                return similarityPart.trim();
            }
        } catch (Exception e) {
            log.error("解析相似度分数失败: {}", e.getMessage());
        }
        return null;
    }

    /**
     * 参数编码方法（参考官方demo）
     * @param map 参数映射
     * @return URL编码后的参数字符串
     */
    public static String params(Map<String, String> map) {
        return map.entrySet().stream()
                .map(entry -> {
                    try {
                        return entry.getKey() + "=" + URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8.toString());
                    } catch (Exception e) {
                        e.printStackTrace();
                        return entry.getKey() + "=" + entry.getValue();
                    }
                })
                .collect(Collectors.joining("&"));
    }

    /**
     * 发送报警通知给旁站监护人员
     */
    private void sendAlarmNotification(String alarmMessage, Integer meetingId, AppEmpDTO appEmpDTO, FaceCheckInResultDTO result, List<Integer> userIds) {
        try {
            // 构建报警消息
            String alarmTitle = "班会签到报警";
            String alarmContent = String.format(
                    "%s\n班会ID: %d\n尝试签到人员: %s\n比对分数: %.2f",
                    alarmMessage,
                    meetingId,
                    appEmpDTO.getEmpName(),
                    result.getFaceScore()
            );

            // 发送推送通知给旁站监护人员
            for (Integer supervisorId : userIds) {
//                messagePushService.pushMessage(
//                        supervisorId,
//                        alarmTitle,
//                        alarmContent,
//                        MessageType.ALARM
//                );
            }

            log.info("已向旁站监护人员发送班会签到报警通知");

        } catch (Exception e) {
            log.error("发送报警通知异常: {}", e.getMessage(), e);
        }
    }

    @Override
    public List<String> getWorkerFaceFeaturesByPlanId(Integer planId) throws BizException {
        List<String> features = new ArrayList<>();
        
        // 这里需要根据业务逻辑实现，获取工作计划关联的施工人员人脸特征
        // 示例实现，实际需要根据数据库设计调整
        AppWorkPlan workPlan = appWorkPlanService.selectById(planId);
        if (workPlan != null) {
            // 根据工作计划获取关联的施工人员，然后获取他们的人脸特征
            // 这里需要根据实际业务逻辑实现
            // features = 从数据库或缓存中获取人脸特征
        }
        
        return features;
    }

    @Override
    public List<Integer> getSupervisorsByPlanId(Integer planId) throws BizException {
        List<Integer> supervisorIds = new ArrayList<>();
        
        // 这里需要根据业务逻辑实现，获取工作计划的旁站监护人员
        // 示例实现，实际需要根据数据库设计调整
        AppWorkPlan workPlan = appWorkPlanService.selectById(planId);
        if (workPlan != null) {
            // 根据工作计划配置获取旁站监护人员ID列表
            // 这里需要根据实际业务逻辑实现
            // supervisorIds = 从数据库或配置中获取监护人员ID
            workPlan.getGuardian1Id();
        }
        
        return supervisorIds;
    }

    private void validateParam(FaceCheckInParam param) throws BizException {
        if (param.getMeetingId() == null) {
            throw new BizException(ResultEnum.FAILURE.getCode(), "班会ID不能为空");
        }
        if (param.getEmpId() == null) {
            throw new BizException(ResultEnum.FAILURE.getCode(), "用户ID不能为空");
        }
        if (param.getFaceImage() == null || param.getFaceImage().isEmpty()) {
            throw new BizException(ResultEnum.FAILURE.getCode(), "人脸图片不能为空");
        }
    }
}